﻿#include "FITKAcousticsVTKGraphObjectLoadExcForMom.h"
#include "FITKAcousticsVTKCommons.h"
#include "FITKAcousticsVTKSharedDataManager.h"
#include "FITKAcousticsVTKGraphActor.h"

#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKCore/FITKDataRepo.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEASubSys.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsAbstractLoad.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKLoadExcitationForceMoments.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsPhysics.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsSpectraManager.h"
#include "FITK_Interface/FITKVTKAlgorithm/FITKGraphActorImage.h"
#include "FITK_Interface/FITKInterfaceModel/FITKCoordinateSystem.h"

#include <vtkImageData.h>
#include <vtkArrowSource.h>
#include <vtkUnstructuredGrid.h>
#include <vtkProperty.h>
#include <vtkGlyph3D.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkDoubleArray.h>
#include <vtkPointData.h>
#include <vtkCoordinate.h>
#include <vtkTransformCoordinateSystems.h>
#include <vtkPointSet.h>
#include <vtkPoints.h>
#include <vtkDataObject.h>
#include <vtkMath.h>

namespace Exchange
{
    FITKAcousticsVTKGraphObjectLoadExcForMom::FITKAcousticsVTKGraphObjectLoadExcForMom(Acoustics::FITKAcousticsAbstractLoad* load)
        : FITKAcousticsVTKGraphObject3D(load)
    {
        if (!load)
        {
            return;
        }

        // Initialize vtk objects.
        init();

        //数据集生成
        if (!generateDataSet())
        {
            return;
        }

        //创建可视化对象
        _graphActor = FITKAcousticsVTKGraphActor::New();
        _graphActor->setGraphObject(this);
        _graphActor->SetPickable(false);
        _graphActor->SetVisibility(true);
        addActor(_graphActor);
        _graphActor->setInputConnection(_glyph3D->GetOutputPort());

        // Update the visibility.
        updateVisibility();

        // Save the data type.
        m_graphInfo.Type = FITKAcousticsVTKCommons::LoadExcForMomGraph;
    }

    FITKAcousticsVTKGraphObjectLoadExcForMom::~FITKAcousticsVTKGraphObjectLoadExcForMom()
    {
        deleteVtkObj(_picData);
        deleteVtkObj(_points);
        deleteVtkObj(_polydata);
        deleteVtkObj(_directions);
        deleteVtkObj(_glyph3D);
    }

    void FITKAcousticsVTKGraphObjectLoadExcForMom::init()
    {
        FITKAcousticsVTKSharedDataManager* sharedDataManager = FITKAcousticsVTKSharedDataManager::GetInstance();
        if (sharedDataManager == nullptr) return;
        double bound[6] = { 0,0,0,0,0,0 };
        if (sharedDataManager->getSEANodesBounds(bound) == false)return;
        double length = std::sqrt(std::pow(bound[0] - bound[3], 2) + std::pow(bound[1] - bound[4], 2) + std::pow(bound[2] - bound[5], 2));
        length = length * 0.1;
        _picData = vtkArrowSource::New();
        //箭头维度
        _picData->SetTipResolution(10);
        //箭头半径
        _picData->SetTipRadius(0.5);
        //箭头长度
        _picData->SetTipLength(0.5);
        //箭柄维度
        _picData->SetShaftResolution(10);
        //箭柄半径
        _picData->SetShaftRadius(0.1);
        //箭头翻转
        _picData->SetInvert(true);
        // 创建一个点集
        _points = vtkPoints::New();

        // 创建一个PolyData对象
        _polydata = vtkPolyData::New();
        _polydata->SetPoints(_points);

        // 创建一个方向数组
        _directions = vtkDoubleArray::New();
        _directions->SetNumberOfComponents(3);

        _polydata->GetPointData()->SetNormals(_directions);

        //使用vtkGlyph3D来生成箭头
        _glyph3D = vtkGlyph3D::New();
        _glyph3D->SetSourceConnection(_picData->GetOutputPort());
        _glyph3D->SetInputData(_polydata);
        _glyph3D->SetVectorModeToUseNormal();
        _glyph3D->SetScaleFactor(length);
    }

    bool FITKAcousticsVTKGraphObjectLoadExcForMom::getDataVisibility()
    {
        bool dataVisible = this->Superclass::getDataVisibility();

        // Get the runtime settings for visibility.
        bool showLoad = getRuntimeSettingAs<bool>(RTS_KEY_VISIBLE_LOADS, true);
        bool showLoadPower = getRuntimeSettingAs<bool>(RTS_KEY_VISIBLE_LOAD_POWER, true);
        return dataVisible && showLoad && showLoadPower;
    }

    void FITKAcousticsVTKGraphObjectLoadExcForMom::update(bool forceUpdate)
    {
        Q_UNUSED(forceUpdate);
        Acoustics::FITKAcousticsAbstractLoad* load = dynamic_cast<Acoustics::FITKAcousticsAbstractLoad*>(_dataObj);
        if (load == nullptr && _graphActor == nullptr)return;
        
        //更新方向
        calculateDirection();

        //更新是否可用颜色
        _graphActor->setColor(FITKAcousticsVTKCommons::getLoadExcForMomColor(load->getEnabledState()));

        // Update visibility.
        updateVisibility();

        //// Update by camera.
        //updateByCamera();
    }

    void FITKAcousticsVTKGraphObjectLoadExcForMom::updateById(int dataId, bool forceUpdate)
    {
        Q_UNUSED(dataId);
        Q_UNUSED(forceUpdate);
    }

    void FITKAcousticsVTKGraphObjectLoadExcForMom::setPickMode(FITKAcousticsVTKCommons::ShapePickMode mode)
    {
        if (!_graphActor){
            return;
        }

        switch (mode)
        {
        case Exchange::FITKAcousticsVTKCommons::PickAll:
            _graphActor->SetPickable(true);
            break;
        case Exchange::FITKAcousticsVTKCommons::PickNone:
        case Exchange::FITKAcousticsVTKCommons::PickVertex:
        case Exchange::FITKAcousticsVTKCommons::PickEdge:
        case Exchange::FITKAcousticsVTKCommons::PickFace:
        case Exchange::FITKAcousticsVTKCommons::PickSolid:
        case Exchange::FITKAcousticsVTKCommons::PickNode:
        case Exchange::FITKAcousticsVTKCommons::PickElement:
        default:
            _graphActor->SetPickable(false);
            break;
        }
    }

    void FITKAcousticsVTKGraphObjectLoadExcForMom::highlight(FITKAcousticsVTKCommons::ShapeType type, QColor color)
    {
        Q_UNUSED(type);
        Q_UNUSED(color);
        if (_graphActor == nullptr && _graphActor->GetProperty())return;
        _graphActor->GetProperty()->SetRepresentation(VTK_WIREFRAME);
    }

    void FITKAcousticsVTKGraphObjectLoadExcForMom::disHighlight()
    {
        if (_graphActor == nullptr && _graphActor->GetProperty())return;
        _graphActor->GetProperty()->SetRepresentation(VTK_SURFACE);
    }

    bool FITKAcousticsVTKGraphObjectLoadExcForMom::generateDataSet()
    {
        return calculateDirection();
    }

    bool FITKAcousticsVTKGraphObjectLoadExcForMom::getDataEnabled()
    {
        Acoustics::FITKAcousticsAbstractLoad* load = dynamic_cast<Acoustics::FITKAcousticsAbstractLoad*>(_dataObj);
        if (!load)
        {
            return false;
        }

        return load->getEnabledState();
    }

    bool FITKAcousticsVTKGraphObjectLoadExcForMom::calculateDirection()
    {
        Acoustics::FITKLoadExcitationForceMoments* load = dynamic_cast<Acoustics::FITKLoadExcitationForceMoments*>(_dataObj);
        if (load == nullptr || _directions == nullptr)return false;
        double pos[3] = { 0,0,0 };
        load->getConnectionLocation(pos);
        int connectDataID = load->getConnectionObjID();
        Acoustics::FITKAbstractSEASubSys* subSys = FITKDATAREPO->getTDataByID<Acoustics::FITKAbstractSEASubSys>(connectDataID);
        if (subSys == nullptr)return false;
        Interface::FITKCoordinateSystem* loadCoorSys = subSys->getCoordinateSys();
        //清空
        _points->Reset();
        _directions->Reset();

        //判断力铺与力矩是否存在
        if (FITKDATAREPO->getDataByID(load->getForceSpectraID()) == nullptr 
            && FITKDATAREPO->getDataByID(load->getMomentSpectraID()) == nullptr) {
            //箭头的位置
            _points->InsertNextPoint(pos[0], pos[1], pos[2]);
            double forceVec[3] = { 0,0,0 }, vec[3] = { 0,0,0 };
            load->getForceOrientationVec(forceVec);
            vectorToLoadCoorSysToWordCoorSys(loadCoorSys, forceVec, vec);
            //箭头的方向
            _directions->InsertNextTuple3(vec[0], vec[1], vec[2]);
        }
        else {
            if (FITKDATAREPO->getDataByID(load->getForceSpectraID())) {
                //箭头的位置
                _points->InsertNextPoint(pos[0], pos[1], pos[2]);
                double forceVec[3] = { 0,0,0 }, vec[3] = { 0,0,0 };
                load->getForceOrientationVec(forceVec);
                vectorToLoadCoorSysToWordCoorSys(loadCoorSys, forceVec, vec);
                //箭头的方向
                _directions->InsertNextTuple3(vec[0], vec[1], vec[2]);
            }
            if (FITKDATAREPO->getDataByID(load->getMomentSpectraID())) {
                //箭头的位置
                double forceVec[3] = { 0,0,0 }, vec[3] = { 0,0,0 };
                load->getMomentOrientationVec(forceVec);
                _points->InsertNextPoint(pos[0], pos[1], pos[2]);
                vectorToLoadCoorSysToWordCoorSys(loadCoorSys, forceVec, vec);
                //箭头的方向
                _directions->InsertNextTuple3(vec[0], vec[1], vec[2]);
            }
        }
        return true;
    }

    void FITKAcousticsVTKGraphObjectLoadExcForMom::vectorToLoadCoorSysToWordCoorSys(Interface::FITKCoordinateSystem* loadCoorSys, 
        double* intVector, double* outVector)
    {
        if (loadCoorSys == nullptr)return;
        double A[3][3] = { 0,0,0,
                           0,0,0,
                           0,0,0 };
        double out[3] = { 0,0,0 };
        double dirX[3] = { 0,0,0 }, dirY[3] = { 0,0,0 }, dirZ[3] = { 0,0,0 };
        loadCoorSys->getDirection1(dirX);
        loadCoorSys->getDirection2(dirY);
        loadCoorSys->getDirection3(dirZ);

        A[0][0] = dirX[0];
        A[1][0] = dirX[1];
        A[2][0] = dirX[2];
        A[0][1] = dirY[0];
        A[1][1] = dirY[1];
        A[2][1] = dirY[2];
        A[0][2] = dirZ[0];
        A[1][2] = dirZ[1];
        A[2][2] = dirZ[2];

        vtkMath::Multiply3x3(A, intVector, out);

        outVector[0] = out[0];
        outVector[1] = out[1];
        outVector[2] = out[2];
    }
}   // namespace Exchange